﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Threading; 

namespace Object_Generator
{
    public partial class ObjectGenerator : Form
    {
        //private const string strConn = "Data Source=10.10.6.53;Initial Catalog=Master;User Id=MidasWeb;Password=tRUbraz8;";
        //private SqlConnection sqlConn = new SqlConnection(tbConnString.Text);


        private SqlConnection sqlConn
        {
            get
            {
                string server = tbServer.Text != "" ? tbServer.Text : ".";
                string database = tbDatabase.Text != "" ? tbDatabase.Text : "PracticeSimple";
                string userName = tbUserName.Text != "" ? tbUserName.Text : "chuck.pfaff";
                string password = tbPassword.Text != "" ? tbPassword.Text : "!!Pfatcat44";

                string strConn = String.Format("Data Source={0};Initial Catalog={1};User Id={2};Password={3};", server, database, userName, password);
                SqlConnection _sqlConn = new SqlConnection(strConn);
                return _sqlConn;
            }
        }

        public ObjectGenerator()
        {
            InitializeComponent();

            populateControls();
        }

        public void populateControls()
        {
            try
            {
                /*tbServer.Text = "10.10.6.53";
                tbDatabase.Text = "CHLive_Dev";
                tbUserName.Text = "";
                tbPassword.Text = "";*/

                SqlDataAdapter sqlDA = new SqlDataAdapter("SELECT object_id, name FROM sys.tables ORDER BY name", sqlConn);

                DataSet dsTables = new DataSet();
                sqlDA.Fill(dsTables);

                BindingSource bs = new BindingSource();
                bs.DataSource = dsTables.Tables[0];
                cbTables.DataSource = bs.DataSource;
                cbTables.DisplayMember = "name";
                cbTables.ValueMember = "object_id";

                List<Item> Objects = new List<Item>();
                Objects.Add(new Item("Model", 1));
                Objects.Add(new Item("Repository", 2));
                Objects.Add(new Item("Form Inputs", 3));
                Objects.Add(new Item("Javascript", 4));

                cbObject.DataSource = Objects;
            }
            catch(Exception ex)
            {
                String x = String.Format(@"Exception occurred in populateControls()
                                            Exception Message: {0}
                                            Stack Trace: {1}", ex.Message, ex.StackTrace);
                tbOutput.Clear();
                tbOutput.Text = x;

            }
        }

        private void btnGenerateObjects_Click(object sender, EventArgs e)
        {
            try
             {
                tbOutput.Clear();

                String sql = String.Format(@"SELECT c.Column_Name,
                    c.Data_Type, 
                    CASE WHEN cu.constraint_name IS NULL THEN 0 ELSE 1 end as IsPrimaryKey,
                    CASE WHEN cuf.constraint_name IS NULL THEN 0 ELSE 1 end as IsForeignKey,
                    p.TABLE_NAME as PrimaryKeyTable, 
                    p.COLUMN_NAME as PrimaryKeyColumn
                    FROM Information_Schema.Columns c
                    LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu
	                    ON c.table_name = cu.table_name
	                    AND c.Column_Name = cu.Column_Name
	                    AND OBJECTPROPERTY(OBJECT_ID(cu.constraint_name), 'IsPrimaryKey') = 1
                    LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE cuf
	                    ON c.table_name = cuf.table_name
	                    AND c.Column_Name = cuf.Column_Name
	                    AND OBJECTPROPERTY(OBJECT_ID(cuf.constraint_name), 'IsForeignKey') = 1
                    LEFT JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
	                    ON cuf.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
                    LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE p
	                    on rc.UNIQUE_CONSTRAINT_NAME = p.CONSTRAINT_NAME
                    WHERE c.table_name = '{0}'", cbTables.Text);

                SqlDataAdapter sqlDA = new SqlDataAdapter(sql, sqlConn);
                DataSet dsColumns = new DataSet();
                sqlDA.Fill(dsColumns);

                switch (cbObject.Text)
                {

                    case "Model":
                        tbOutput.Text = GenerateModelObject(cbTables.Text, dsColumns.Tables[0]);
                        break;

                    case "Form Inputs":
                        tbOutput.Text = GenerateFormInputs(cbTables.Text, dsColumns.Tables[0]);
                        break;

                    case "Repository":
                        tbOutput.Text = GenerateRepositoryObject(cbTables.Text, dsColumns.Tables[0]);
                        break;

                    case "Javascript":
                        tbOutput.Text = GenerateJavascript(cbTables.Text, dsColumns.Tables[0]);
                        break;

                    default:
                        tbOutput.Text = "Unimplemented option";
                        break;
                }

             }
             catch(Exception ex)
            {
                String x = String.Format(@"Exception occurred in btnGenerateObjects_Click()
                                            Exception Message: {0}
                                            Stack Trace: {1}", ex.Message, ex.StackTrace);
                tbOutput.Clear();
                tbOutput.Text = x;

            }

            
        }


        private string GenerateModelObject(string tableName, DataTable dtColumns)
        {
            StringBuilder sbModel = new StringBuilder();
            sbModel.AppendFormat("/*************************   Auto Generated Model Code For {0} table     Generated @ {1} *************************/", tableName, DateTime.Now.ToString());
            sbModel.AppendLine();

            sbModel.AppendFormat(@"

using System;
using System.Collections.Generic;

              namespace BusinessObjects
              {{
                  public partial class {0}
                  {{", tableName);
                sbModel.AppendLine();

                foreach(DataRow dr in dtColumns.Rows)
                {
                    if (dr["IsForeignKey"].ToString() == "1")
                    {
                      sbModel.AppendFormat("                     public {0} {0} {{get; set;}}", dr["PrimaryKeyTable"].ToString(), dr["Column_Name"].ToString());
                      sbModel.AppendLine();
                    }
                    else
                    {
                      sbModel.AppendFormat("                     public  {0} {1} {{get; set;}}", ConvertType(dr["Data_Type"].ToString()), dr["Column_Name"].ToString());                  
                      sbModel.AppendLine();
                    }
                }

                sbModel.Append(@"                  }
              }


");

            return sbModel.ToString();
        }


        private string GenerateMappingObject(string tableName, DataTable dtColumns)
        {

            StringBuilder sbMapping = new StringBuilder();

            sbMapping.AppendFormat("/*************************   Auto Generated Mapping Code For {0} table     Generated @ {1} *************************/", tableName, DateTime.Now.ToString());
            sbMapping.AppendLine();

            sbMapping.AppendFormat(@"

using FluentNHibernate.Mapping;
using BusinessObjects;

              namespace MidasLiveAdmin.Mappings
              {{
                  public class {0}Map : ClassMap<{0}>
                  {{
                    public {0}Map()
                    {{
                      this.Table(""{0}"");", tableName);
            sbMapping.AppendLine();

            foreach (DataRow dr in dtColumns.Rows)
            {
                if (dr["IsPrimaryKey"].ToString() == "1")
                {
                    sbMapping.AppendFormat("                      Id(x => x.{0}).GeneratedBy.Identity();", dr["Column_Name"].ToString());
                    sbMapping.AppendLine();
                }
                else if (dr["IsForeignKey"].ToString() == "1")
                {
                    sbMapping.AppendFormat("                      References(x => x.{0}).Column(\"{1}\").LazyLoad();", dr["PrimaryKeyTable"].ToString(), dr["Column_Name"].ToString());
                    sbMapping.AppendLine();
                }
                else
                {
                    sbMapping.AppendFormat("                      Map(x => x.{0}).Column(\"{0}\");", dr["Column_Name"].ToString());
                    sbMapping.AppendLine();
                }
            }

            sbMapping.Append(@"                     }
                  }
              }


");

            return sbMapping.ToString();
        }

        private string GenerateRepositoryObject(string tableName, DataTable dtColumns)
        {

            StringBuilder sbRepository = new StringBuilder();

            sbRepository.AppendFormat("/*************************   Auto Generated Repository Code For {0} table     Generated @ {1} *************************/", tableName, DateTime.Now.ToString());
            sbRepository.AppendLine();

            DataRow[] rows = dtColumns.Select();
            DataRow primaryKey = rows.FirstOrDefault(x => x["IsPrimaryKey"].ToString() == "1");

            string primaryKeyField = "ID";

            if (primaryKey != null)
            {
                primaryKeyField = primaryKey["Column_Name"].ToString();

            }

            StringBuilder sbDataMapping = new StringBuilder();
            foreach (DataRow dr in dtColumns.Rows)
            {
                sbDataMapping.AppendFormat("businessObject.{0} = dataObject.{0};{1}", dr["Column_Name"], System.Environment.NewLine);
            }

            StringBuilder sbBusinessMapping = new StringBuilder();
            foreach (DataRow dr in dtColumns.Rows)
            {
                sbBusinessMapping.AppendFormat("dataObject.{0} = businessObject.{0};{1}", dr["Column_Name"], System.Environment.NewLine);
            }

            sbRepository.AppendFormat(@"

using System;
using System.Collections.Generic;
using System.Linq;
using BusinessObjects;

              namespace DataLayer
              {{
                  public partial class {0}Repository
                  {{
                    private PracticeSimpleDataContext dB;


                    /// <summary>
                    /// Retrieve an {0} by its {1} (Primary Key)
                    /// </summary>
                    /// <param name=""{1}"">The ID of the <see cref=""{0}""/> to retrieve</param>
                    /// <returns>A <see cref=""{0}""/> object</returns>
                    public BusinessObjects.{0} Select(int {1})
                    {{
                        {0} retObject;

                        using (dB = new PracticeSimpleDataContext())
                        {{
                            retObject = (from x in dB.{0}s where x.{1} == {1} select x).SingleOrDefault();
                        }}
            
                        return ConvertToBusinessObject(retObject);
                    }}

                    /// <summary>
                    /// Return a list of {0} objects
                    /// </summary>
                    /// <returns>A List of type <see cref=""{0}""/></returns>
                    public List<BusinessObjects.{0}> SelectAll()
                    {{
                        List<BusinessObjects.{0}> retObject = new List<BusinessObjects.{0}>();

                        using (dB = new PracticeSimpleDataContext())
                        {{
                            var {0}List = (from x in dB.{0}s select x).ToList();
                            
                            foreach({0} obj in {0}List)
                            {{
                                retObject.Add(ConvertToBusinessObject(obj));
                            }}
                    
                        }}
                        return retObject;
                    }}
             

                    /// <summary>
                    /// Accepts a {0} Business object, converts it and saves it to the database
                    /// </summary>
                    /// <returns>Void</returns>
                    public BusinessObjects.{0} Save(BusinessObjects.{0} businessObject)
                    {{         
                        {0} db{0};            
                        using (dB = new PracticeSimpleDataContext())
                        {{
                            db{0} = ConvertToDataObject(businessObject);
                            dB.{0}s.InsertOnSubmit(db{0});
                            dB.SubmitChanges();
                        }}

                        return ConvertToBusinessObject(db{0});
                    }}

                    /// <summary>
                    /// Accepts the Primary Key of a {0}, finds it in the database and deletes it
                    /// </summary>
                    /// <param name=""{1}"">The ID of the <see cref=""{0}""/> to retrieve</param>
                    /// <returns>Void</returns>
                    public void Delete(int {1})
                    {{
                         using (dB = new PracticeSimpleDataContext())
                        {{
                            DataLayer.{0} obj = (from x in dB.{0}s where x.{0}ID == {0}ID select x).SingleOrDefault();
                            dB.{0}s.DeleteOnSubmit(obj);
                            dB.SubmitChanges();
                        }}
                    }}
                    
                    /// <summary>
                    /// Converts a {0} data object to a {0} business object
                    /// </summary>
                    /// <returns>A business object of type <see cref=""{0}""/></returns>
                    public BusinessObjects.{0} ConvertToBusinessObject(DataLayer.{0} dataObject)
                    {{
                        BusinessObjects.{0} businessObject = new BusinessObjects.{0}();

                        {3}

                        return businessObject;

                    }}
                    
                    /// <summary>
                    /// Converts a {0} business object to a {0} data object
                    /// </summary>
                    /// <returns>A data object of type <see cref=""{0}""/></returns>
                    public DataLayer.{0} ConvertToDataObject(BusinessObjects.{0} businessObject)
                    {{
                        DataLayer.{0} dataObject = new DataLayer.{0}();

                        {4}

                        return dataObject;
                    }}
                }}
            }}


", tableName, primaryKeyField, tableName.ToLower(), sbDataMapping.ToString(), sbBusinessMapping.ToString());
           

            return sbRepository.ToString();
        }



        private string GenerateRepositoryInterface(string tableName)
        {


            StringBuilder sbRepositoryInterface = new StringBuilder();

            sbRepositoryInterface.AppendFormat("/*************************   Auto Generated Repository Code For {0} table     Generated @ {1} *************************/", tableName, DateTime.Now.ToString());
            sbRepositoryInterface.AppendLine();

            sbRepositoryInterface.AppendFormat(@"
                            using System;
                            using System.Collections;
                            using System.Collections.Generic;
                            using PracticeSimple.BusinessObjects;

                            namespace DataLayer
                            {{
                                public interface I{0}Repository
                                {{
                                    {0} Get{0}(int {0}ID);
                                    IList<{0}> Get{0}List();
                                    void Save({0} {1});
                                    void Delete(int subID);

                                }}
                            }}", tableName, tableName.ToLower());



            return sbRepositoryInterface.ToString();

         }



        private string GenerateFormInputs(string tableName, DataTable dtColumns)
        {
            StringBuilder sbFormInputs= new StringBuilder();
            sbFormInputs.AppendFormat("/*************************   Auto Generated Model Code For {0} table     Generated @ {1} *************************/{2}", tableName, DateTime.Now.ToString(), System.Environment.NewLine);
            sbFormInputs.AppendLine("<div class='inputContainer'>");

                 
            foreach (DataRow dr in dtColumns.Rows)
            {
                sbFormInputs.AppendFormat("<div class='input'><label for='tb{0}'>{0}:</label><input type='text' id='tb{0}'/></div>{1}", dr["Column_Name"], System.Environment.NewLine);
            }


            sbFormInputs.AppendLine("</div>");

            return sbFormInputs.ToString();
        }


        private string GenerateJavascript(string tableName, DataTable dtColumns)
        {
            StringBuilder sbJavascriptObject= new StringBuilder();
            sbJavascriptObject.AppendFormat("/*************************   Auto Generated Model Code For {0} table     Generated @ {1} *************************/{2}", tableName, DateTime.Now.ToString(), System.Environment.NewLine);
            sbJavascriptObject.AppendFormat("var {0}Object = {{ {1}", tableName, System.Environment.NewLine);

            foreach (DataRow dr in dtColumns.Rows)
            {
                sbJavascriptObject.AppendFormat("'{0}' :$('#tb{0}').val(),{1}", dr["Column_Name"], System.Environment.NewLine);
            }


            sbJavascriptObject.AppendLine("};");

            sbJavascriptObject.AppendFormat(@"

            var url = '{0}/Save{0}';

            $.ajax({{
                url: url,
                data: {{ {0}JSON: {0} }},
                type: 'post',
                dataType: 'json',
                success: function (data) {{
           
                    alert('{0} created');
                }},
                error: function (data) {{
                    alert('Awww Snap...We encountered trouble saving the {0}.');
                }}
            }});", tableName);

            return sbJavascriptObject.ToString();
        }



        private string ConvertType(string SQLType)
        {
            string dotnetType;

            switch(SQLType)
            {

                case "int":
                    dotnetType = "int";
                    break;

                case "bit":
                    dotnetType = "bool";
                    break;
                case "datetime":
                    dotnetType = "DateTime";
                    break;

                default:
                     dotnetType = "string";
                    break;
            }

            return dotnetType;
        }

        // Content item for the combo box
        private class Item
        {
            public string Name;
            public int Value;
            public Item(string name, int value)
            {
                Name = name; Value = value;
            }
            public override string ToString()
            {
                // Generates the text shown in the combo box
                return Name;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            populateControls();
        }

        private void btnCopy_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.Clipboard.SetText(tbOutput.Text);
        }

     }
}
